#ifndef MPHTTPCLIENT_H
#define MPHTTPCLIENT_H

/******************************
 *
 * 名   称：   支持 HTTP 协议的客户端编程工具包
 * 用   途：   1. 获取或设置 HTTP 客户端的默认参数，包括：网络地址、请求头、超时时长
 *            2. 执行同步的Http请求。包括：get、post、put、delete、download等请求
 *            3. 执行异步的Http请求，同上
 *            4. 取消所有正在运行的异步请求
 * 作用范围：   公共的
 * 创建时间：   2022-10-03
 * 备   注：   1. 代码中包括 HttpRequestContent 请求体的相关定义。HttpRequestContent 与 HttpRequestMessage 属于聚合关系，
 *            2. HttpConnection 具有 HttpGenericConnection、HttpSslConnection两个派生类，分别对应HTTP及HTTPS连接两种情况。
 *            3. HttpConnection及其派生类建议均通过代码中定义的CreateXXXX相关函数创建，不要自行实例化
 * 参考：
 * https://blog.csdn.net/wangzhiyu1980/article/details/45010885
 * https://www.cnblogs.com/ylcc-zyq/p/14959136.html
 * https://www.cnblogs.com/my_life/articles/5331789.html                [boost asio 介绍]
 *
 ******************************/

#include "boost/asio/io_context.hpp"
#include "mpHttpRequestMessage.h"
#include "mpHttpResponseMessage.h"

namespace MP{
namespace HTTP{

/*****************************************
 * HttpClientBase 基类
 *****************************************/

class HttpClientBase
{
public:
    virtual ~HttpClientBase() = default;
protected:
    HttpClientBase();
public:
    Url& getBaseAddress();
    HttpRequestHeaders& getDefaultRequestHeaders();

    virtual void initHttpRequestMessageHeaders(HttpRequestMessage::ptr_s requestMessage);

    //设置建立连接的超时时间（单位：秒，默认值5）
    void set_connect_timeout(int sec);
    //获取建立连接的超时时间（单位：秒，默认值5）
    int get_connect_timeout() const;
    //设置请求中写入data的超时时间（单位：秒，默认值30）
    void set_write_timeout(int sec);
    //获取请求中写入data的超时时间（单位：秒，默认值30）
    int get_write_timeout() const;
    //设置请求中读取data的超时时间（单位：秒，默认值30）
    void set_read_timeout(int sec) ;
    //获取请求中读取data的超时时间（单位：秒，默认值30）
    int get_read_timeout() const;
protected:
    Url _baseAddress;
    HttpRequestHeaders _defaultRequestHeaders;

    int _connect_timeout;
    int _write_timeout;
    int _read_timeout;
};

/*****************************************
 * HttpClient 同步请求类
 *****************************************/

class HttpClient : public HttpClientBase
{
public:
    using ptr_s = std::shared_ptr<HttpClient>;
    virtual ~HttpClient() override = default;
protected:
    HttpClient();
public:

    virtual void send(HttpRequestMessage::ptr_s httpRequest,
                      HttpResponseMessage::ptr_s httpResponse,
                      func_send_progress_callback&& progress_callback = nullptr) = 0;

    //head
    virtual HttpResponseMessage::ptr_s head(const std::string& relativeUri,
                                            func_send_progress_callback&& progress_callback = nullptr) = 0;

    //get
    virtual HttpResponseMessage::ptr_s get(const std::string& relativeUri,
                                           func_send_progress_callback&& progress_callback = nullptr) = 0;

    virtual bool getStream(const std::string& relativeUri,
                           std::stringstream& stream,
                           func_send_progress_callback&& progress_callback = nullptr) = 0;

    virtual bool download(const std::string& relativeUri,
                          const std::string& filePath,
                          std::size_t fileOffset = 0,
                          func_send_progress_callback&& progress_callback = nullptr) = 0;

    //post
    virtual HttpResponseMessage::ptr_s post(const std::string& relativeUri,
                                            HttpRequestContent::ptr_s content,
                                            func_send_progress_callback&& progress_callback = nullptr) = 0;
    //put
    virtual HttpResponseMessage::ptr_s put(const std::string& relativeUri,
                                           HttpRequestContent::ptr_s content,
                                           func_send_progress_callback&& progress_callback = nullptr) = 0;
    //delete
    virtual HttpResponseMessage::ptr_s del(const std::string& relativeUri,
                                           func_send_progress_callback&& progress_callback = nullptr) = 0;

};  //HttpClient

/*****************************************
 * HttpClient 异步请求类
 *****************************************/

class HttpClientAsync : public HttpClientBase
{
public:
    using ptr_s = std::shared_ptr<HttpClientAsync>;
    virtual ~HttpClientAsync() override = default;
protected:
    HttpClientAsync();
public:
    virtual void cancel() = 0;
    virtual void sendAsync(HttpRequestMessage::ptr_s httpRequest,
                           HttpResponseMessage::ptr_s httpResponse,
                           func_send_complete_callback&& complete_callback = nullptr,
                           func_send_progress_callback&& progress_callback = nullptr) = 0;

    //head
    virtual void headAsync(const std::string& relativeUri,
                           func_send_complete_callback&& complete_callback = nullptr,
                           func_send_progress_callback&& progress_callback = nullptr) = 0;

    //get
    virtual void getAsync(const std::string& relativeUri,
                          func_send_complete_callback&& complete_callback = nullptr,
                          func_send_progress_callback&& progress_callback = nullptr) = 0;

    virtual void downloadAsync(const std::string& relativeUri,
                               const std::string& filePath,
                               std::size_t fileOffset = 0,
                               func_send_complete_callback&& complete_callback = nullptr,
                               func_send_progress_callback&& progress_callback = nullptr) = 0;

    //post
    virtual void postAsync(const std::string& relativeUri,
                           HttpRequestContent::ptr_s content,
                           func_send_complete_callback&& complete_callback = nullptr,
                           func_send_progress_callback&& progress_callback = nullptr) = 0;
    //put
    virtual void putAsync(const std::string& relativeUri,
                          HttpRequestContent::ptr_s content,
                          func_send_complete_callback&& complete_callback = nullptr,
                          func_send_progress_callback&& progress_callback = nullptr) = 0;
    //delete
    virtual void delAsync(const std::string& relativeUri,
                          func_send_complete_callback&& complete_callback = nullptr,
                          func_send_progress_callback&& progress_callback = nullptr) = 0;
};


//创建 HttpClient
HttpClient::ptr_s createHttpClient(/*bool useShardContext*/);
HttpClient::ptr_s createHttpClientUseName(const std::string& name);
HttpClient::ptr_s createHttpClientUseUrl(const Url& baseAddress);

HttpClientAsync::ptr_s createHttpClientAsync(boost::asio::io_context& io_context);
HttpClientAsync::ptr_s createHttpClientAsyncUseName(boost::asio::io_context& io_context,
                                                    const std::string& name);
HttpClientAsync::ptr_s createHttpClientAsyncUseUrl(boost::asio::io_context& io_context,
                                                   const Url& baseAddress);



}   //HTTP
}   //MP



#endif // MPHTTPCLIENT_H
